package com.taskflow.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import com.taskflow.common.Result;

/**
 * 日志监控Controller
 */
@Slf4j
@RestController
@RequestMapping("/log-monitor")
@CrossOrigin
public class LogMonitorController {

    private static final String LOG_FILE = "logs/application.log";
    private static final ExecutorService executor = Executors.newCachedThreadPool();
    private static final List<SseEmitter> emitters = new CopyOnWriteArrayList<>();

    /**
     * 获取最近的日志（最后N行）
     */
    @GetMapping("/recent")
    public Result<List<String>> getRecentLogs(@RequestParam(defaultValue = "100") int lines) {
        List<String> result = new ArrayList<>();
        File logFile = new File(LOG_FILE);
        
        if (!logFile.exists()) {
            result.add("日志文件不存在: " + LOG_FILE);
            return Result.success(result);
        }

        try {
            // 依次尝试多种编码读取
            List<Charset> candidates = new ArrayList<>();
            candidates.add(StandardCharsets.UTF_8);
            tryAddCharset(candidates, "GBK");
            tryAddCharset(candidates, "GB18030");
            candidates.add(Charset.defaultCharset());

            List<String> allLines = null;
            Exception lastEx = null;
            for (Charset cs : candidates) {
                try {
                    allLines = Files.readAllLines(Paths.get(LOG_FILE), cs);
                    lastEx = null;
                    break;
                } catch (Exception ex) {
                    lastEx = ex;
                }
            }

            if (allLines == null) {
                throw lastEx != null ? lastEx : new IOException("无法读取日志文件");
            }

            int start = Math.max(0, allLines.size() - lines);
            result = allLines.subList(start, allLines.size());
        } catch (Exception e) {
            log.error("读取日志文件失败", e);
            result.add("读取日志失败: " + e.getMessage());
        }

        return Result.success(result);
    }

    private void tryAddCharset(List<Charset> list, String name) {
        try {
            list.add(Charset.forName(name));
        } catch (Exception ignore) { }
    }

    /**
     * 实时推送日志（SSE）
     */
    @GetMapping("/stream")
    public SseEmitter streamLogs() {
        SseEmitter emitter = new SseEmitter(0L); // 永不超时
        emitters.add(emitter);

        emitter.onCompletion(() -> emitters.remove(emitter));
        emitter.onTimeout(() -> emitters.remove(emitter));
        emitter.onError((e) -> emitters.remove(emitter));

        // 发送初始消息
        executor.execute(() -> {
            try {
                emitter.send(SseEmitter.event()
                        .data("连接成功，开始监控日志...")
                        .name("init"));

                // 发送最近50行日志
                Result<List<String>> recent = getRecentLogs(50);
                List<String> recentLogs = recent.getData() != null ? recent.getData() : new ArrayList<>();
                for (String line : recentLogs) {
                    emitter.send(SseEmitter.event()
                            .data(line)
                            .name("log"));
                    Thread.sleep(10); // 避免发送太快
                }

                // 开始监控新日志
                monitorLogFile(emitter);
            } catch (Exception e) {
                log.error("SSE发送失败", e);
                emitter.completeWithError(e);
            }
        });

        return emitter;
    }

    /**
     * 监控日志文件变化
     */
    private void monitorLogFile(SseEmitter emitter) {
        File logFile = new File(LOG_FILE);
        if (!logFile.exists()) {
            return;
        }

        BufferedReader reader = null;
        try {
            // 依次尝试多种编码打开
            List<Charset> candidates = new ArrayList<>();
            candidates.add(StandardCharsets.UTF_8);
            tryAddCharset(candidates, "GBK");
            tryAddCharset(candidates, "GB18030");
            candidates.add(Charset.defaultCharset());

            Exception openEx = null;
            for (Charset cs : candidates) {
                try {
                    reader = new BufferedReader(new InputStreamReader(new FileInputStream(logFile), cs));
                    openEx = null;
                    break;
                } catch (Exception ex) {
                    openEx = ex;
                }
            }
            if (reader == null) {
                throw openEx != null ? openEx : new IOException("无法以任意编码打开日志文件");
            }

            // 跳到文件末尾
            reader.skip(logFile.length());

            while (!Thread.currentThread().isInterrupted()) {
                String line = reader.readLine();
                if (line != null) {
                    // 有新日志，推送给所有客户端
                    for (SseEmitter e : emitters) {
                        try {
                            e.send(SseEmitter.event()
                                    .data(line)
                                    .name("log"));
                        } catch (Exception ex) {
                            emitters.remove(e);
                        }
                    }
                } else {
                    // 没有新数据，等待一会儿
                    Thread.sleep(1000);
                }
            }
        } catch (Exception e) {
            log.error("监控日志文件失败", e);
        } finally {
            if (reader != null) {
                try { reader.close(); } catch (Exception ignore) {}
            }
        }
    }

    /**
     * 清空日志
     */
    @DeleteMapping("/clear")
    public Result<Void> clearLogs() {
        try {
            File logFile = new File(LOG_FILE);
            if (logFile.exists()) {
                Files.write(Paths.get(LOG_FILE), new byte[0]);
                return Result.success("日志已清空", null);
            }
            return Result.error("日志文件不存在");
        } catch (IOException e) {
            log.error("清空日志失败", e);
            return Result.error("清空日志失败: " + e.getMessage());
        }
    }
}

